package net.xo68.destiny.core.discovery;

import net.xo68.destiny.contract.domain.node.NodeRegistry;
import net.xo68.destiny.contract.enums.NodeTypeEnum;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 节点注册映射持久存储
 * @author wuxie
 * @version 2020-11-18
 */
public class NodeMapStore {

    private final ConcurrentLinkedQueue<NodeRegistry> manageNodeList;

    private final ConcurrentHashMap<String, Set<NodeRegistry>> workNodeMap;

    private final ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();


    public NodeMapStore() {
        this.manageNodeList=new ConcurrentLinkedQueue<>();
        this.workNodeMap=new ConcurrentHashMap<>();

    }

    /**
     * 添加管理节点
     * @param nodeRegistry
     */
    public void addManageNode(NodeRegistry nodeRegistry){
        readWriteLock.writeLock().lock();
        try{
            if(!this.manageNodeList.contains(nodeRegistry)){
                this.manageNodeList.offer(nodeRegistry);
            }
        }finally {
            readWriteLock.writeLock().unlock();
        }

    }

    /**
     * 添加工作节点
     * @param nodeRegistry
     */
    public void addWorkNode(NodeRegistry nodeRegistry){
        readWriteLock.writeLock().lock();
        try{
            checkAndCreateWorkGroup(nodeRegistry.getWorkGroup());
            Set<NodeRegistry> workNodes=this.workNodeMap.get(nodeRegistry.getWorkGroup());
            if(!workNodes.contains(nodeRegistry)){
                workNodes.add(nodeRegistry);
            }
        }finally {
            readWriteLock.writeLock().unlock();
        }

    }

    /**
     * 移除工作节点
     * @param nodeRegistry
     */
    public void removeWorkNode(NodeRegistry nodeRegistry){
        readWriteLock.writeLock().lock();
        try{
            checkAndCreateWorkGroup(nodeRegistry.getWorkGroup());
            Set<NodeRegistry> workNodes=this.workNodeMap.get(nodeRegistry.getWorkGroup());
            if(workNodes.contains(nodeRegistry)){
                workNodes.remove(nodeRegistry);
            }
        }finally {
            readWriteLock.writeLock().unlock();
        }

    }

    /**
     * 管理节点
     * @return
     */
    public Collection<NodeRegistry> getManageNodes(){
        readWriteLock.readLock().lock();
        try{
            return Collections.unmodifiableCollection(this.manageNodeList);
        }finally {
            readWriteLock.readLock().unlock();
        }

    }

    /**
     * 返回管理节点host
     * @return
     */
    public List<String> getManageHosts(){
        Collection<NodeRegistry> manageNodes=getManageNodes();
        final List<String> hosts=new ArrayList<>();
        manageNodes.forEach(nodeRegistry -> {
            hosts.add(nodeRegistry.getNodeHost());
        });
        return hosts;
    }

    /**
     * 指定分组的工作节点
     * @param workGroupName
     * @return
     */
    public Collection<NodeRegistry> getWorkNodesByGroupName(final String workGroupName){
        readWriteLock.readLock().lock();
        try{
            if(StringUtils.isBlank(workGroupName)){
                return null;
            }
            checkAndCreateWorkGroup(workGroupName);
            return Collections.unmodifiableCollection(this.workNodeMap.get(workGroupName));
        }finally {
            readWriteLock.readLock().unlock();
        }
    }

    /**
     * 指定工作组的工作节点host
     * @param workGroupName
     * @return
     */
    public List<String> getWorkHostsByGroupName(final String workGroupName){
        Collection<NodeRegistry> manageNodes=getWorkNodesByGroupName(workGroupName);
        final List<String> hosts=new ArrayList<>();
        manageNodes.forEach(nodeRegistry -> {
            hosts.add(nodeRegistry.getNodeHost());
        });
        return hosts;
    }

    /**
     * 合并注册信息到存储中
     * @param nodeRegistryList
     */
    public void merge(final List<NodeRegistry> nodeRegistryList){
        readWriteLock.writeLock().lock();
        try{
            if(nodeRegistryList==null || nodeRegistryList.isEmpty()){
                return;
            }
            //清理原有节点注册信息
            if(nodeRegistryList.stream().anyMatch(nodeRegistry -> {
                return nodeRegistry.getNodeType()== NodeTypeEnum.MANAGER;
            })){
                //如果没有管理节点，就不清理管理节点
                manageNodeList.clear();
            }
            workNodeMap.forEach((group,node)->{
                node.clear();
            });

            for (NodeRegistry nodeRegistry: nodeRegistryList){
                switch (nodeRegistry.getNodeType()){
                    case MANAGER:
                        addManageNode(nodeRegistry);
                        break;
                    case WORKER:
                        addWorkNode(nodeRegistry);
                        break;
                    default:
                        break;
                }
            }
        }finally {
            readWriteLock.writeLock().unlock();
        }

    }

    /**
     * 检查并创建工作组容器
     * @param workGroupName
     */
    private void checkAndCreateWorkGroup(final String workGroupName){
        if(!this.workNodeMap.containsKey(workGroupName)){
            HashSet<NodeRegistry> works=new HashSet<>();
            this.workNodeMap.put(workGroupName,works);
        }
    }
}
